﻿using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System.Security.Authentication;
using K9Nano.AspNetCore.Filters;
using Microsoft.Extensions.Logging;
using K9Nano.Exceptions;

namespace K9Nano.AspNetCore.Filters;

public class K9ExceptionFilter : IExceptionFilter
{
    private readonly ILogger _logger;

    public K9ExceptionFilter(ILogger<K9ExceptionFilter> logger)
    {
        _logger = logger;
    }

    public void OnException(ExceptionContext context)
    {
        string error = "请求失败，请稍后再试";
        int code = 500;
        int statusCode = 500;
        string action;

        action = context.HttpContext.Request.GetDisplayUrl();

        if (context.Exception is FriendlyException userFriendlyException)
        {
            code = userFriendlyException.Error;
            error = userFriendlyException.Message;
            statusCode = 400;
        }
        else if (context.Exception is AuthenticationException authorizationException)
        {
            code = 403;
            statusCode = 403;
            error = authorizationException.Message;
        }

        if (code == 500)
        {
            _logger.LogError(context.Exception,"请求起源：{Action}", action);
        }

        context.ExceptionHandled = true;

        if (context.Filters.OfType<ApiControllerAttribute>().Any())
        {
            var apiResult = new ApiResponse(code, "请求失败", error);
            context.Result = new JsonResult(apiResult)
            {
                StatusCode = statusCode
            };

            if (context.HttpContext.Items[ApiLoggingWrapper.Name] is ApiLoggingWrapper loggingWrapper)
            {
                loggingWrapper.Result = apiResult;
            }
        }
        else
        {
            var model = new ErrorViewModel
            {
                Error = error,
                Path = action,
                StatusCode = statusCode,
                RequestId = context.HttpContext.TraceIdentifier
            };

            var view = new ViewResult
            {
                ViewName = "Error",
                StatusCode = statusCode,
                ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
                {
                    Model = model
                }
            };

            context.Result = view;
        }
    }
}